package com.gzx.plugin.tjzy.modular.phone.error.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import com.gzx.plugin.tjzy.modular.phone.dto.GzxPhoneStatusDto;
import com.gzx.plugin.tjzy.modular.phone.error.bo.GzxErrorPhoneAddBo;
import com.gzx.plugin.tjzy.modular.phone.error.bo.GzxErrorPhoneQueryBo;
import com.gzx.plugin.tjzy.modular.phone.error.dto.GzxLYJJRespDto;
import com.gzx.plugin.tjzy.modular.phone.error.entity.GzxErrorPhone;
import com.gzx.plugin.tjzy.modular.phone.error.mapper.GzxErrorPhoneMapper;
import com.gzx.plugin.tjzy.modular.phone.error.service.GzxErrorPhoneDbService;
import com.gzx.plugin.tjzy.modular.phone.error.service.GzxErrorPhoneService;
import com.gzx.plugin.tjzy.modular.phone.error.vo.GzxErrorPhoneVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;
import vip.xiaonuo.auth.core.util.StpLoginUserUtil;
import vip.xiaonuo.common.consts.IntConstant;
import vip.xiaonuo.common.mvc.service.impl.BaseServiceImpl;
import vip.xiaonuo.common.tenant.TenantContext;
import vip.xiaonuo.common.util.*;
import vip.xiaonuo.common.wechat.enums.WechatNotificationType;

import java.util.*;
import java.util.stream.Collectors;

import static org.apache.commons.lang.StringEscapeUtils.escapeSql;

/**
 * @author zjt
 * @description
 * @date 2025/6/10 16:48
 */
@Slf4j
@Service
@DS("tjzy-async")
public class GzxErrorPhoneServiceImpl extends BaseServiceImpl<GzxErrorPhoneAddBo, GzxErrorPhoneVo, GzxErrorPhoneQueryBo, GzxErrorPhoneMapper, GzxErrorPhone> implements GzxErrorPhoneService {

    private final GzxErrorPhoneDbService errorPhoneDbService;

    public GzxErrorPhoneServiceImpl(GzxErrorPhoneMapper baseMapper, GzxErrorPhoneDbService errorPhoneDbService) {
        super(baseMapper);
        this.errorPhoneDbService = errorPhoneDbService;
    }

    @Override
    public void insert(GzxErrorPhoneAddBo bo) {
        bo.setSource(2);
        bo.setBelongingMonth(Integer.valueOf(CommonDateUtil.getCurrentMonth()));
        super.insert(bo);
    }

    @Override
    protected LambdaQueryWrapper<GzxErrorPhone> buildQueryWrapper(GzxErrorPhoneQueryBo queryBo) {
        LambdaQueryWrapper<GzxErrorPhone> wrapper = Wrappers.<GzxErrorPhone>lambdaQuery()
                // 手机号
                .eq(StringUtils.isNotBlank(queryBo.getPhone()), GzxErrorPhone::getPhone, CommonCryptogramUtil.doSm1AesEncrypt(queryBo.getPhone()))
                .eq(!ObjectUtils.isEmpty(queryBo.getType()), GzxErrorPhone::getType, queryBo.getType())
                .eq(0 != queryBo.getBelongingMonth(), GzxErrorPhone::getBelongingMonth, queryBo.getBelongingMonth())
                // 按照创建日期范围查询
                .between(StringUtils.isNotBlank(queryBo.getBeginTime()) && StringUtils.isNotBlank(queryBo.getEndTime()), GzxErrorPhone::getCreateTime, queryBo.getBeginTime(), queryBo.getEndTime());
        return wrapper.orderByDesc(GzxErrorPhone::getId);
    }

    /**
     * 校验异常手机号
     *
     * @param phoneList
     * @return
     */
    @Override
    public List<GzxPhoneStatusDto> verifyPhone(List<String> phoneList, String userId, String tenantId) {
        List<GzxPhoneStatusDto> resultList = new ArrayList<>();
        if (CollUtil.isNotEmpty(phoneList)) {
            //校验异常（停空）手机号
            List<GzxErrorPhone> errorPhoneList = errorPhoneDbService.selectList(Wrappers.<GzxErrorPhone>lambdaQuery()
                    .select(GzxErrorPhone::getPhone, GzxErrorPhone::getType)
                    .in(GzxErrorPhone::getPhone, phoneList.stream().map(CommonCryptogramUtil::doSm1AesEncrypt).toList())
                    .eq(GzxErrorPhone::getBelongingMonth, CommonDateUtil.getCurrentMonth()));
            errorPhoneList.forEach(s -> resultList.add(new GzxPhoneStatusDto(s.getPhone(), s.getType(), null)));
            //过滤出未在数据库命中的手机号
            List<String> missingErrorPhoneList = phoneList.stream().filter(phone -> errorPhoneList.stream().noneMatch(e -> e.getPhone().equals(phone))).toList();
            if (CollUtil.isNotEmpty(missingErrorPhoneList)) {
                resultList.addAll(apiVerifyError(missingErrorPhoneList, userId, tenantId));
            }
        }
        return resultList;
    }

    //异常手机号导入
    @Override
    public String importExcel(GzxErrorPhoneAddBo bo, MultipartFile multipartFile) {
        long start = System.currentTimeMillis();
        //excel的数据
        List<GzxErrorPhoneVo> excelVoList = CommonExcelUtil.importExcel(multipartFile, GzxErrorPhoneVo.class);
        List<GzxErrorPhone> errorPhoneList = MapstructUtils.convert(excelVoList, GzxErrorPhone.class);

        if (ObjectUtils.isEmpty(errorPhoneList)) {
            return "Excel为空";
        }

        //去掉 errorPhoneList 中 phone 为空的数据
        errorPhoneList = errorPhoneList.stream().filter(v -> !ObjectUtils.isEmpty(v.getPhone())).toList();

        if (ObjectUtils.isEmpty(errorPhoneList)) {
            return "Excel为空";
        }

        //获取登录人信息
        String userId = StpLoginUserUtil.getLoginUser().getId();
        String tenantId = StpLoginUserUtil.getLoginUser().getTenantId();

        //批量处理每次1000条
        List<List<GzxErrorPhone>> bacthList = Lists.partition(errorPhoneList, IntConstant.VALUE_1000);
        for (List<GzxErrorPhone> errorBatch : bacthList) {
            String batchSql = errorBatch.stream().map(s -> String.format("('%s', '%s','%s', '%s', '%s', '%s', '%s', '%s')", escapeSql(CommonCryptogramUtil.doSm1AesEncrypt(s.getPhone())), escapeSql(String.valueOf(bo.getType())), 2, CommonDateUtil.getCurrentMonth(), null, CommonDateUtil.dateTimeToStr(new Date()), escapeSql(tenantId), escapeSql(userId))).collect(Collectors.joining(", ")).replace("'null'", "null");
            baseMapper.insertBatchSql(batchSql);
            CommonSleepUtil.sleep(IntConstant.VALUE_100);
        }
        log.info("导入成功，共{}条，耗时{}秒", errorPhoneList.size(), System.currentTimeMillis() - start);
        return "成功";
    }


    /**
     * 查询异常手机号数据
     *
     * @param lambdaQueryWrapper
     * @return
     */
    @Override
    public List<GzxErrorPhone> selectList(LambdaQueryWrapper<GzxErrorPhone> lambdaQueryWrapper) {
        return baseMapper.selectList(lambdaQueryWrapper);
    }

    private List<GzxPhoneStatusDto> apiVerifyError(List<String> phoneList, String userId, String tenantId) {
        Map<String, Object> formMap = new HashMap<>();
        formMap.put("appId", "893d45c01f1e4828912c4b8087fe1263");
        formMap.put("appKey", "cf1de62ef494446eb348fc02d0bb09b9");
        formMap.put("mobile", String.join(",", phoneList));
        String resp = CommonHttpUtil.postByForm("http://api.shoujikonghao.com/api/end/high", formMap, "临沂精简停空校验接口");
        List<GzxPhoneStatusDto> phoneStatusDtoList = new ArrayList<>();
        try {
            GzxLYJJRespDto lyjjRespDto = JSONObject.parseObject(resp, GzxLYJJRespDto.class);
            if (lyjjRespDto != null) {
                if ("200000".equals(lyjjRespDto.getCode()) && CollUtil.isNotEmpty(lyjjRespDto.getData())) {
                    lyjjRespDto.getData().forEach(s -> phoneStatusDtoList.add(new GzxPhoneStatusDto(s.getMobile(), mappingStatus(s.getStatus()), JSON.toJSONString(s))));
                    Thread.startVirtualThread(() -> TenantContext.ignoreHandle(() -> errorPhoneDbService.saveBatch(phoneStatusDtoList, userId, tenantId)));
                } else if ("510101".equals(lyjjRespDto.getCode())) {
                    //余额不足
                    CommonWechatUtil.sendMessage("停空余额告警【异常】", WechatNotificationType.TASK_ERROR, List.of("ZhuJingTian-BeiJing"), "调用临沂精简停空校验接口", "余额不足！！！");
                } else {
                    phoneList.forEach(s -> phoneStatusDtoList.add(new GzxPhoneStatusDto(s, 0, null)));
                }
            } else {
                log.error("临沂精简停空校验返回失败：{}", resp);
                phoneList.forEach(s -> phoneStatusDtoList.add(new GzxPhoneStatusDto(s, 0, null)));
            }
        } catch (Exception e) {
            log.error("临沂精简停空校验解析JSON失败：", e);
            phoneList.forEach(s -> phoneStatusDtoList.add(new GzxPhoneStatusDto(s, 0, null)));
        }
        return phoneStatusDtoList;
    }

    private Integer mappingStatus(Integer status) {
        return switch (status) {
            case 0 -> 1;
            case 1, 3, 4 -> 0;
            default -> status;
        };
    }
}
